package com.yunji.system.business;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import com.yunji.common.base.BaseBusiness;
import com.yunji.common.constant.CacheCode;
import com.yunji.common.enums.common.ErrorEnum;
import com.yunji.common.exception.ServiceException;
import com.yunji.common.model.dto.SmsCountDTO;
import com.yunji.common.model.dto.SmsDTO;
import com.yunji.common.model.enums.NumberType;
import com.yunji.common.utils.RandomUtils;
import com.yunji.common.utils.TimeUtils;
import com.yunji.common.utils.bean.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


/**
 * @Project: yunji-coffee
 * @Package: com.yunji.common.business
 * @Title: SmsBusiness
 * <p>
 * History:
 * Date                     Version     Author          Summary
 * ============================================================
 * 2024-10-11 16:12:21      V1.0        HuaAo       新建类
 */
@Component
public class SmsBusiness extends BaseBusiness {

    private static final String PRODUCT = "Dysmsapi";
    private static final String DOMAIN = "dysmsapi.aliyuncs.com";

    @Value("${aliyun.sms.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.sms.accessKeySecret}")
    private String accessKeySecret;
    @Value("${aliyun.sms.templateCode}")
    private String templateCode;
    @Value("${aliyun.sms.signName}")
    private String signName;

    private static final String SEND_NUM = "num";

    private static final String TIME = "time";

    @Resource
    private CaptchaService captchaService;

    /**
     * @param dto
     * @Title send
     * @Desc 发送验证码
     * @Date 2024-10-11 16:50:59.194
     */
    public String send(SmsDTO dto) {
        // 校验入参
        checkDTO(dto);

        CaptchaVO vo = new CaptchaVO();
        BeanUtils.clone(dto, vo);

        String number = dto.getNumber();

        // 校验短信当天发送次数和发送频率
        String redisCountValue = redisCache.get(CacheCode.SMS_SEND_COUNT + number);
        SmsCountDTO smsCountDTO = new SmsCountDTO();
        //取得当前时间和次数0点的时间差 作为缓存时间
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        int redisSetTime = Integer.parseInt(String.valueOf(TimeUtils.getNextDate().getTime() - timestamp.getTime()));//
        if (!ObjectUtils.isEmpty(redisCountValue)) {
            JSONObject jsonObject = JSONObject.parseObject(redisCountValue);

            int num = Integer.parseInt(jsonObject.getString(SEND_NUM));
            // 每天一个手机号获取次数为20次 后续放入配置文件
            if (num >= 20) {
                throw new RuntimeException(ErrorEnum.BUSINESS_121007.getText());
            }
            //检测发送频繁
            long time = Long.parseLong(jsonObject.getString(TIME));
            long diff = Math.abs(new Date().getTime() / 1000 - time); // 计算差异的毫秒数
            logs.info("发送短信:手机号：{},发送次数：{},发送频率：{}", number, num, diff);
            if (diff <= 60) {
                throw new RuntimeException(ErrorEnum.BUSINESS_121008.getText());
            }
            num = num + 1;
            smsCountDTO.setNum(num);
        } else {
            //短信未发送过，初始化记数
            smsCountDTO.setNum(1);
        }
        smsCountDTO.setTime(new Date().getTime() / 1000);
        redisCache.set(CacheCode.SMS_SEND_COUNT + number, JSON.toJSONString(smsCountDTO), redisSetTime, TimeUnit.MILLISECONDS);

        // 发送手机验证码
        try {
            sendPhone(number);
        } catch (ClientException e) {
            throw new RuntimeException(e);
        }

        return "发送成功";
        // 发送邮箱验证码
    }

    /**
     * @param phone 手机号
     * @Title sendPhone
     * @Desc 发送手机验证码
     * @Date 2024-10-11 18:26:37.749
     */
    private void sendPhone(String phone) throws ClientException {
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", PRODUCT, DOMAIN);
        IAcsClient acsClient = new DefaultAcsClient(profile);
        SendSmsRequest request = new SendSmsRequest();
        request.setPhoneNumbers(phone);
        request.setSignName(signName);
        request.setTemplateCode(templateCode);
        JSONObject code = new JSONObject();
        String captcha = RandomUtils.getRandomMath(4);
        code.put("code", captcha);
        redisCache.set(CacheCode.SMS_KEY + phone, captcha, 5, TimeUnit.MINUTES);
        request.setTemplateParam(code.toString());
        SendSmsResponse response = acsClient.getAcsResponse(request);
        String resultCode = response.getCode();
        if (!Objects.equals("OK", resultCode)) {
            throw new ServiceException(response.getMessage());
        }
    }

    /**
     * @param dto SmsDTO
     * @Title checkDTO
     * @Desc 校验号码参数
     * @Date 2024-10-11 16:50:15.537
     */
    private void checkDTO(SmsDTO dto) {
        String number = dto.getNumber();
        Integer type = dto.getType();
        logs.info("【发送验证码】号码:{},号码类型 0-手机号 1-邮箱:{}", number, type);

        Assert.isTrue(BeanUtils.isNotNull(number), "请输入号码");
        Assert.isTrue(BeanUtils.isNotNull(type), "请选择号码类型");

        if (Objects.equals(NumberType.PHONE.getCode(), type)) {
            Assert.isTrue(number.matches("^1[345789]\\d{9}$"), ErrorEnum.CHECKED_111004.getText());
        } else {
            Assert.isTrue(number.matches("^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"), ErrorEnum.CHECKED_111012.getText());
        }

    }
}